using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Glee.Drawing;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Reflection;
using System.Configuration;
using manticore;

namespace manticore
{
    public partial class Form1 : Form
    {
        ToolTip toolTip1 = new ToolTip();
        public Form1()
        {
            this.Load += new EventHandler(Form1_Load);
            InitializeComponent();

            this.toolTip1.Active = true;
            toolTip1.AutoPopDelay = 5000;
            toolTip1.InitialDelay = 1000;
            toolTip1.ReshowDelay = 500;
            // Force the ToolTip text to       
            toolTip1.ShowAlways = true;
        }

        void Form1_Load(object sender, EventArgs e)
        {
            //  gViewer.RemoveToolbar();
            gViewer.SelectionChanged +=
              new EventHandler(gViewer_SelectionChanged);

            gViewer.MouseClick += new MouseEventHandler(gViewer_MouseClick);
        }

        void gViewer_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
                MessageBox.Show("right button");
            if (e.Button == System.Windows.Forms.MouseButtons.Left && selectedObject is Microsoft.Glee.Drawing.Node)
            {               
                 foreach (var en in gViewer.Entities)
                     if (en.DrawingObject.UserData !=null)
                     {
                         this.propertyGrid1.SelectedObject = en.DrawingObject.UserData;
                          //(gViewer.SelectedObject as Node).UserData;
                     }
            }
        }


        object selectedObjectAttr;
        object selectedObject;
        void gViewer_SelectionChanged(object sender, EventArgs e)
        {
            if (selectedObject != null)
            {
                if (selectedObject is Edge)
                    (selectedObject as Edge).Attr = selectedObjectAttr as EdgeAttr;
                else if (selectedObject is Node)
                {
                    selectedObject = gViewer.SelectedObject;
                    this.propertyGrid1.SelectedObject = (selectedObject as Node).UserData;
                }
                selectedObject = null;
            }

            if (gViewer.SelectedObject == null)
            {
                label1.Text = "No object under the mouse";
                this.gViewer.SetToolTip(toolTip1, "");

            }
            else
            {
                selectedObject = gViewer.SelectedObject;

                if (selectedObject is Edge)
                {
                    selectedObjectAttr = (gViewer.SelectedObject as Edge).Attr.Clone();
                    (gViewer.SelectedObject as Edge).Attr.Color = Microsoft.Glee.Drawing.Color.Magenta;
                    (gViewer.SelectedObject as Edge).Attr.Fontcolor = Microsoft.Glee.Drawing.Color.Magenta;
                    Edge edge = gViewer.SelectedObject as Edge;


                    //here you can use e.Attr.Id or e.UserData to get back to you data
                    this.gViewer.SetToolTip(this.toolTip1, String.Format("edge from {0} {1}", edge.Source, edge.Target));

                }
                else if (selectedObject is Node)
                {
                    selectedObjectAttr = (selectedObject as Node).UserData;
                    
                    selectedObjectAttr = (gViewer.SelectedObject as Node).Attr.Clone();
                    (selectedObject as Node).Attr.Color = Microsoft.Glee.Drawing.Color.Magenta;
                    (selectedObject as Node).Attr.Fontcolor = Microsoft.Glee.Drawing.Color.Magenta;

                    foreach (var en in gViewer.Entities)
                    {
                        if (en.SelectedForDragging)
                            this.propertyGrid1.SelectedObject = en.DrawingObject.UserData;
                    }

                    //(selectedObject as Node).UserData = (gViewer.SelectedObject as Node).UserData;
                    //this.propertyGrid1.SelectedObject = selectedObject;



                    //here you can use e.Attr.Id to get back to your data <- comment from Glee Author
                    //here you CANNOT use e.Attr.Id to get back to your data <- comment from me

                 //   this.gViewer.SetToolTip(toolTip1, String.Format("node {0}", (selectedObject as Node).Attr.Label));
                }
              //  label1.Text = selectedObject.ToString();
            }
            gViewer.Invalidate();
        }

        private void DrawNetworkNode(Graph g, Node[] nodes)
        {
            foreach (Node n in nodes)
            {
                n.UserData = "some user data";
                g.AddNode(n.Id);

            }

            this.propertyGrid1.SelectedObject = nodes[0].UserData;

            //Edge edge = (Edge)g.AddEdge("S24", "27");
            //edge.Attr.Label = "Edge Label Test"; // text to the righmost edge of the graph
            //edge.EdgeAttr.AddStyle(Style.Diagonals);

            //g.AddEdge("S24", "25");
            //edge = g.AddEdge("S1", "10") as Edge;

            //edge.Attr.Label = "Init";
            //edge.Attr.ArrowHeadAtTarget = ArrowStyle.Tee;
            ////  edge.Attr.Weight = 10;
            //edge = g.AddEdge("S1", "2") as Edge;
            //// edge.Attr.Weight = 10;
            //g.AddEdge("S35", "36");
            //g.AddEdge("S35", "43");
            //g.AddEdge("S30", "31");
            //g.AddEdge("S30", "33");
            //g.AddEdge("9", "42");
            //g.AddEdge("9", "T1");
            //g.AddEdge("25", "T1");
            //g.AddEdge("25", "26");
            //g.AddEdge("27", "T24");
            //g.AddEdge("2", "3");
            //g.AddEdge("2", "16");
            //g.AddEdge("2", "17");
            //g.AddEdge("2", "T1");
            //g.AddEdge("2", "18");
            //g.AddEdge("10", "11");
            //g.AddEdge("10", "14");
            //g.AddEdge("10", "T1");
            //g.AddEdge("10", "13");
            //g.AddEdge("10", "12");
            //g.AddEdge("31", "T1");
            //edge = (Edge)g.AddEdge("31", "32");
            //edge.Attr.ArrowHeadAtTarget = ArrowStyle.Tee;
            //edge.Attr.LineWidth = 10;

            //edge = (Edge)g.AddEdge("33", "T30");
            //edge.Attr.LineWidth = 3;
            //edge.Attr.AddStyle(Microsoft.Glee.Drawing.Style.Dashed);
            //g.AddEdge("33", "34");
            //g.AddEdge("42", "4");
            //g.AddEdge("26", "4");
            //g.AddEdge("3", "4");
            //g.AddEdge("16", "15");
            //g.AddEdge("17", "19");
            //g.AddEdge("18", "29");
            //g.AddEdge("11", "4");
            //g.AddEdge("14", "15");
            //g.AddEdge("37", "39");
            //g.AddEdge("37", "41");
            //g.AddEdge("37", "38");
            //g.AddEdge("37", "40");
            //g.AddEdge("13", "19");
            //g.AddEdge("12", "29");
            //g.AddEdge("43", "38");
            //g.AddEdge("43", "40");
            //g.AddEdge("36", "19");
            //g.AddEdge("32", "23");
            //g.AddEdge("34", "29");
            //g.AddEdge("39", "15");
            //g.AddEdge("41", "29");
            //g.AddEdge("38", "4");
            //g.AddEdge("40", "19");
            //g.AddEdge("4", "5");
            //g.AddEdge("19", "21");
            //g.AddEdge("19", "20");
            //g.AddEdge("19", "28");
            //g.AddEdge("5", "6");
            //g.AddEdge("5", "T35");
            //g.AddEdge("5", "23");
            //g.AddEdge("21", "22");
            //g.AddEdge("20", "15");
            //g.AddEdge("28", "29");
            //g.AddEdge("6", "7");
            //g.AddEdge("15", "T1");
            //g.AddEdge("22", "23");
            //g.AddEdge("22", "T35");
            //g.AddEdge("29", "T30");
            //g.AddEdge("7", "T8");
            //g.AddEdge("23", "T24");
            //g.AddEdge("23", "T1");


            //Node node = g.FindNode("S1") as Node;
            //node.Attr.Label = "Label Test";
            //CreateSourceNode(g.FindNode("S1") as Node);
            //CreateSourceNode(g.FindNode("S24") as Node);
            //CreateSourceNode(g.FindNode("S35") as Node);


            //CreateTargetNode(g.FindNode("T24") as Node);
            //CreateTargetNode(g.FindNode("T1") as Node);
            //CreateTargetNode(g.FindNode("T30") as Node);
            //CreateTargetNode(g.FindNode("T8") as Node);

            //layout the graph and draw it
            gViewer.Graph = g;
        }




        private void button1_Click(object sender, EventArgs e)
        {

            XmlReader reader;
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ProhibitDtd = false;

            settings.ValidationType = ValidationType.DTD;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {

                try
                {
                    String fileName = openFileDialog1.FileName;
                    reader = XmlReader.Create(openFileDialog1.FileName, settings);
                    XmlDocument doc = new XmlDocument();
                    doc.Load(reader);
                    
                    this.propertyGrid1.SelectedObject = sender;

                    // graph generation starts here

                    //this is abstract.dot of GraphViz
                    Graph g = new Graph("graph");
                    g.GraphAttr.NodeAttr.Padding = 3;

                    DrawNetworkNode(g, GenerateGraph(doc));

                    // graph generation ends here
                }
                catch (XmlException)
                {

                }
                catch (XmlSchemaException)
                {
                    MessageBox.Show("The version of Nmap used may be old as the output XML does not appear valid. Just so you know", "Validation Issue", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                }
                finally
                {

                }
            }
        }

        private static void CreateSourceNode(Node a)
        {
            a.Attr.Shape = Microsoft.Glee.Drawing.Shape.Box;
            a.Attr.XRad = 3;
            a.Attr.YRad = 3;
            a.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.Green;
            a.Attr.LineWidth = 10;
        }

        private void CreateTargetNode(Node a)
        {
            a.Attr.Shape = Microsoft.Glee.Drawing.Shape.DoubleCircle;
            a.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.LightGray;

            a.Attr.LabelMargin = -4;
        }

        private void recalculateLayoutButton_Click(object sender, EventArgs e)
        {
            this.gViewer.Graph = this.propertyGrid1.SelectedObject as Microsoft.Glee.Drawing.Graph;
        }

        /// <summary>
        /// Reads application settings into the XpathQueryList Dictionary
        /// </summary>
        private Dictionary<string, string> GetHostXPathStatements()
        {
            Dictionary<string, string> XPathQueryList = new Dictionary<string, string>();
            try
            {
                foreach (SettingsProperty prop in Manticore.Properties.Settings.Default.Properties)
                {
                    XPathQueryList.Add(prop.Name, prop.DefaultValue.ToString());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return XPathQueryList;
        }

        private Node[] GenerateGraph(XmlDocument nMapOutput)
        {
            Dictionary<string, string> XPathQueries = GetHostXPathStatements();

            //this is abstract.dot of GraphViz
            Graph g = new Graph("graph");
            g.GraphAttr.NodeAttr.Padding = 3;

            XmlNode root = nMapOutput.DocumentElement;

            XPathNavigator navigator = nMapOutput.CreateNavigator();

            Dictionary<string, string> NodeResults = new Dictionary<string, string>();

            string result;

            XPathNodeIterator xNodes = navigator.Select("/nmaprun/host");

            nodes = new NetworkNode[xNodes.Count];

            foreach (XPathNavigator child in xNodes)
            {
                nodes[xNodes.CurrentPosition] = new NetworkNode();
                nodes[xNodes.CurrentPosition].Host = "no host info";
                nodes[xNodes.CurrentPosition].Accuracy = "no accuracy information";
                nodes[xNodes.CurrentPosition].Accuracy = "no accuracy information";
                nodes[xNodes.CurrentPosition].Host = "no host information";
                nodes[xNodes.CurrentPosition].Ipaddress = "no IP address information";
                nodes[xNodes.CurrentPosition].IsUp = false;
                nodes[xNodes.CurrentPosition].Mac = "no MAC address found";
                nodes[xNodes.CurrentPosition].OsFamily = "no OS information";
                nodes[xNodes.CurrentPosition].OsGeneration = "no OS information";
                nodes[xNodes.CurrentPosition].OsVendor = "no OS information";

                // iterate through the list of keys
                foreach (string s in XPathQueries.Keys)
                {
                    // extract the XPath 2.0 expressions
                    if (XPathQueries.TryGetValue(s, out result) == true)
                    {
                        XPathExpression expression = XPathExpression.Compile(result);
                        try
                        {
                            if (!child.SelectSingleNode(expression).IsEmptyElement)
                            {
                                switch (s)
                                {
                                    case "NMapAddress":
                                        nodes[xNodes.CurrentPosition].Ipaddress = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapHostname":
                                        nodes[xNodes.CurrentPosition].Host = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapMAC":
                                        nodes[xNodes.CurrentPosition].Mac = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapOSFamily":
                                        nodes[xNodes.CurrentPosition].OsFamily = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapOSVendor":
                                        nodes[xNodes.CurrentPosition].OsVendor = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapOSGeneration":
                                        nodes[xNodes.CurrentPosition].OsGeneration = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapOSAccuracy":
                                        nodes[xNodes.CurrentPosition].Accuracy = child.SelectSingleNode(expression).Value;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapIsThisHostUp":
                                        bool up = child.SelectSingleNode(expression).Value == "up" ? true : false;
                                        nodes[xNodes.CurrentPosition].IsUp = up;
                                        Console.WriteLine("Expression: " + expression.Expression + " Result: " + child.SelectSingleNode(expression).Value);
                                        break;
                                    case "NMapInUSePorts":
                                        //we're going to do something else here
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                        catch (NullReferenceException)
                        {
                            //NetworkNode node = new Node("") as NetworkNode;
                            switch (s)
                            {
                                case "NMapAddress":
                                    nodes[xNodes.CurrentPosition].Ipaddress = "No IP info";
                                    
                                    break;
                                case "NMapHostname":
                                    nodes[xNodes.CurrentPosition].Host = "no host info";
                                    
                                    break;
                                case "NMapMAC":
                                    nodes[xNodes.CurrentPosition].Mac = "no mac info";
                                    //node.. = nodes[nodes.CurrentPosition].Mac;
                                    break;
                                case "NMapOSFamily":
                                    nodes[xNodes.CurrentPosition].OsFamily = "no OS found";
                                    break;
                                case "NMapOSVendor":
                                    nodes[xNodes.CurrentPosition].OsVendor = "no vendor details";
                                     break;
                                case "NMapOSGeneration":
                                    nodes[xNodes.CurrentPosition].OsGeneration = "unknown";
                                    break;
                                case "NMapOSAccuracy":
                                    nodes[xNodes.CurrentPosition].Accuracy = "unknown";
                                    break;
                                case "NMapIsThisHostUp":
                                    //bool up = false;
                                    break;
                                case "NMapInUSePorts":
                                    //we're going to do something else here
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
                
                xNodes.MoveNext();
            }

            Node[] MSAGLNodes = new Node[nodes.Length];

            for (int i=0;i<nodes.Length;i++)
            {
                 if (nodes[i].Host.Length > 0)
                {
                    MSAGLNodes[i] = new Node(nodes[i].Ipaddress);
                    g.AddNode(nodes[i].Ipaddress);
                    MSAGLNodes[i].UserData = nodes[i];
                }
            }
            return MSAGLNodes;
        }
    }
}
